#pragma once

#include <gtl/type/type.h>
#include <gtl/atom/atom.h>
#include <gtl/type/inner.h>
#include <gtl/string/tchar.h>
#include <gtl/endian/endian.h>
#include <gtl/factory/factory.h>

//#include <sstream>

namespace gtl
{

namespace atom
{

class idetails
{
public:
	virtual bool parse(atom* patom) = 0;
};

enum endian_e { big_endian, little_endian, };

typedef gtl::factory::factory<idetails, int> factory;

template<class Atom, uint32 Identify, endian_e Endian = big_endian, 
		 int Offset = 0, class Memento = gtl::type::null, int Length = 0>
class details 
	: public idetails
	, public Memento
	, public gtl::factory::reg<Atom, factory, Identify>
{
protected:
	virtual ~details() {}

protected:
	enum { fixed_length = Length, };

public:
	typedef details<Atom, Identify, Endian, Offset, Memento, Length> base_type;

public:
	bool parse(atom* patom)
	{
		if(patom == NULL)
			return false;

		if(sizeof(idetails) % 4 != 0 || sizeof(reg_type) % 4 != 0)
			return false;

		const uint32 fix_len = sizeof(idetails) + sizeof(reg_type);
		const uint32 len = Length == 0 ? sizeof(Atom) - fix_len - Offset : Length;
		if(patom->length() < len || len % 4 != 0)
			return false;

		uchar buffer[len] = {0};
		patom->read(0, len, buffer);

		if(Endian == big_endian)
		{
			for(int i = 0; i < len; i += 4)
			{
				*((uint32*)this + (fix_len + i + Offset) / 4) = gtl::endian::get_be32(buffer + i);
			}
		}
		else
		{
			for(int i = 0; i < len; i += 4)
			{
				*((uint32*)this + (fix_len + i + Offset) / 4) = gtl::endian::get_le32(buffer + i);
			}
		}

		return true;
	}

protected:
	uint32 get_uint32(atom* patom, uint32 offset)
	{
		uint32 value = 0;
		patom->read(offset, 4, (uchar*)&value);
		return gtl::endian::get_be32((uchar*)&value);
	}
};

//namespace helper
//{
//	template<class Atom, uint32 Identify, int Offset = 4, class Memento = typename Atom, int Length = 0>
//	class mhxx
//		: public iparser
//		, public Memento
//		, protected details<Atom, Identify, Offset, Memento, Length>
//	{
//	public:
//		virtual ~mhxx()
//		{
//		}
//
//	public:
//		// override parser
//		virtual uint32 read(uchar* pBuffer, uint32 length)
//		{
//			int len = (int)sizeof(Memento) - Offset;
//			if(pBuffer == NULL || length == 0 || len <= 0)
//				return 0;
//
//			len = std::min((uint32)len, header_length);
//			memcpy(pBuffer, reinterpret_cast<uchar*>(static_cast<Memento*>(this)) + Offset, len);
//
//			return len;
//		}
//	};
//}
//
//template<class Atom, uint32 Identify, int Offset = 4, class Memento = typename Atom, int Length = 0, bool IsLeaf = false>
//class mhxx : public helper::mhxx<Atom, Identify, Offset, Memento, Length>
//{
//public:
//	virtual ~mhxx()
//	{
//	}
//
//public:
//	// override parser
//	virtual uint32 length()
//	{ 
//		return Memento::header_length; 
//	}
//};
//
//template<class Atom, uint32 Identify, int Offset, class Memento, int Length>
//class mhxx<Atom, Identify, Offset, Memento, Length, true> 
//	: public helper::mhxx<Atom, Identify, Offset, Memento, Length>
//{
//public:
//	virtual ~mhxx()
//	{
//	}
//
//public:
//	// override parser
//	virtual uint32 length()
//	{ 
//		return Memento::total_length; 
//	}
//};

} // end of namespace atom

} // end of namespace gtl